import { ASTUtils, Selectors } from '@angular-eslint/utils';
import type { TSESTree } from '@typescript-eslint/utils';
import { createESLintRule } from '../utils/create-eslint-rule';

export type Options = [];
export type MessageIds = 'noOutputOnPrefix';
export const RULE_NAME = 'no-output-on-prefix';
const STYLE_GUIDE_LINK =
  'https://angular.dev/guide/components/outputs#choosing-event-names';

export default createESLintRule<Options, MessageIds>({
  name: RULE_NAME,
  meta: {
    type: 'suggestion',
    docs: {
      description: `Ensures that output bindings, including aliases, are not named "on", nor prefixed with it. See more at ${STYLE_GUIDE_LINK}`,
      recommended: 'recommended',
    },
    schema: [],
    messages: {
      noOutputOnPrefix: `Output bindings, including aliases, should not be named "on", nor prefixed with it (${STYLE_GUIDE_LINK})`,
    },
  },
  defaultOptions: [],
  create(context) {
    const outputOnPattern = /^on(([^a-z])|(?=$))/;
    const selectors = [
      Selectors.OUTPUTS_METADATA_PROPERTY_LITERAL,
      Selectors.OUTPUT_ALIAS,
      Selectors.OUTPUT_PROPERTY_OR_GETTER,
    ].join(',');

    return {
      [selectors](
        node: TSESTree.Identifier | TSESTree.Literal | TSESTree.TemplateElement,
      ) {
        const [propertyName, aliasName] = ASTUtils.getRawText(node)
          .replace(/\s/g, '')
          .split(':');

        if (
          !outputOnPattern.test(propertyName) &&
          !outputOnPattern.test(aliasName)
        ) {
          return;
        }

        context.report({
          node,
          messageId: 'noOutputOnPrefix',
        });
      },
    };
  },
});

export const RULE_DOCS_EXTENSION = {
  rationale:
    "Angular's template syntax allows both '(eventName)' and 'on-eventName' for event bindings. If you prefix an output with 'on', this creates awkward template syntax like '(onUserClick)' or the even more redundant 'on-onUserClick'. This violates the principle of least surprise and makes templates harder to read. Instead, name outputs as simple actions or events (like 'userClick'), which Angular templates will bind as '(userClick)' or 'on-userClick'.",
};
